package com.dmzc.stage1.chapter5;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeoutException;
import static java.lang.System.currentTimeMillis;
import static java.lang.Thread.currentThread;
public class BooleanLock implements Lock {
    private Thread currentThread;
    private boolean locked = false;
    private final List<Thread> blockedList = new ArrayList<>();

    /***
     * @throws InterruptedException
     * lock可以多次获得，如果锁已经被别人获得，则加入阻塞队列
     * lock锁没有被别人获得，则从阻塞队列删除
     * 捕获异常又抛出，两次异常
     */
    @Override
    public void lock() throws InterruptedException {
        synchronized (this) {
            while (locked) {
                final Thread tempThread=currentThread();
                try{
                    blockedList.add(currentThread);
                    //waitting后会解锁，睡眠状态结束后notifyAll会再次进行锁的竞争
                    this.wait();
                }catch (InterruptedException e){
                    blockedList.remove(tempThread);
                    throw e;
                }

            }
            //如果不包含当前线程，则不会做出改变
            blockedList.remove(currentThread());
            this.locked = true;
            this.currentThread = currentThread();
        }
    }

    @Override
    public void lock(long mills) throws InterruptedException, TimeoutException {
        synchronized (this) {
            if (mills <= 0) {
                this.lock();
            } else {
                long remainingMills = mills;
                //具体的结束时间点
                long endMills = currentTimeMillis() + remainingMills;
                final Thread tempThread=currentThread();
                while (locked) {
                    //todo
                    if (remainingMills <= 0) {
                        throw new TimeoutException("can not get the lock during"
                                + mills + "ms.");
                    }
                    if (!blockedList.contains(currentThread())) {
                        blockedList.add(currentThread());
                    }
                    //如果自身已经等待了指定时间，锁仍然没有释放，会抛出超时异常
                    try{
                        this.wait(remainingMills);
                        remainingMills=endMills-currentTimeMillis();
                    }catch(InterruptedException e){
                        blockedList.remove(tempThread);
                        throw e;
                    }
                                    }
                blockedList.remove(currentThread());
                this.locked = true;
                this.currentThread = currentThread();
            }
        }
    }

    @Override
    public void unlock() {
        synchronized (this) {
            if (currentThread == currentThread()) {
                this.locked = false;
                System.out.println(currentThread().getName()+"release the lock");
                this.notifyAll();
            }
        }
    }

    @Override
    public List<Thread> getBlockedThreads() {
        return Collections.unmodifiableList(blockedList);
    }
}
